﻿using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using NLog;
using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using CsvHelper;
using Microsoft.Win32;
using System.IO;
using System.Data;
using CsvHelper.Configuration;
using System.Globalization;
using System.Reflection.PortableExecutable;
using PortCommunicate.LogEntries;
using System.Windows;


namespace PortCommunicate.ViewModels
{
    public partial class MainWindowViewModel:ObservableObject
    {
        private readonly string logFilePath = " ";
        private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
        SerialPort serialPort;
        [ObservableProperty] string[] portNames = SerialPort.GetPortNames();

        [ObservableProperty] string selectedPort;

        [ObservableProperty] bool selectComEnable = true;

        [ObservableProperty] string connectButtonContent = "Open";

        [ObservableProperty] string sendData;

        [ObservableProperty] int delayTime = 10;

        [ObservableProperty] int boundRate = 115200;

        [ObservableProperty] double processProgress;//进度条显示百分比

        [ObservableProperty] bool isProcessing = false;//进度条滚动，无百分比

        [ObservableProperty] Visibility isProcessingVisiable = Visibility.Collapsed;//进度条显示

        public MainWindowViewModel()
        {
            serialPort = new SerialPort();
            selectedPort = portNames[0];
        }
        [RelayCommand]
        public void Connect()
        {
            try
            {
                if (!serialPort.IsOpen)
                {
                    serialPort = new SerialPort(SelectedPort, BoundRate, Parity.None, 8, StopBits.One);
                    serialPort.Open();
                    Logger.Info($"{SelectedPort}连接成功");
                    ConnectButtonContent = "Close";
                    SelectComEnable = false;
                }
                else
                {
                    serialPort.Close();
                    ConnectButtonContent = "Open";
                    Logger.Info($"{SelectedPort}断开连接");
                    SelectComEnable = true;
                }
            }
            catch (Exception ex)
            {
                Logger.Error(ex.Message);
                return;
            }
        }
        [RelayCommand]
        public void Send()
        {
            if (serialPort.IsOpen)
            {
                byte requestByte = 0xA9;
                byte[] wData = { 0x50, 0x00, 0x00, 0x00 };

                byte[] datas = new byte[wData.Length + 1];
                datas[0] = requestByte;
                Array.Copy(wData, 0, datas, 1, wData.Length);

                serialPort.Write(datas, 0, datas.Length);
                Logger.Info($"Data sent: {BitConverter.ToString(datas)}");
            }
            else
            {
                Logger.Warn("请先打开COM");
            }
        }

        int totalRow = 0;
        private string filePath;
        [RelayCommand]
        public async void Import()
        {
            try
            {
                OpenFileDialog openFileDialog = new OpenFileDialog
                {
                    Filter = "CSV files (*.csv)|*.csv",
                    Title = "选择CSV文件"
                };

                if (openFileDialog.ShowDialog() == true)
                {
                    filePath = openFileDialog.FileName;

                    var count = GetTotalLineCount(filePath);
                    totalRow = count;
                    Logger.Info($"文件{filePath}导入成功，行数: {count}");
                }
            }
            catch(Exception ex)
            {
                Logger.Error(ex.Message);
            }
        }
        public int GetTotalLineCount(string filePath)
        {
            // 直接通过流读取所有行并计数（包含空行）
            using (var reader = new StreamReader(filePath))
            {
                int count = 0;
                while (reader.ReadLine() != null)
                {
                    count++;
                }
                return count;
            }
        }

        /// <summary>
        /// 把 "0xA5" 或 "0x0BB11477" 这样的字符串解析成字节数组
        /// 允许带或不含 0x 前缀，允许大小写
        /// </summary>
        private static byte[]? ParseHexString(string? hex)
        {
            if (string.IsNullOrWhiteSpace(hex))
                return null;

            hex = hex.Trim().Replace("0x", "", StringComparison.OrdinalIgnoreCase);
            if (hex.Length % 2 == 1)      // 奇数位补 0
                hex = "0" + hex;

            var bytes = new byte[hex.Length / 2];
            for (int i = 0; i < bytes.Length; i++)
            {
                bytes[i] = byte.Parse(hex.Substring(i * 2, 2),
                                      NumberStyles.HexNumber,
                                      CultureInfo.InvariantCulture);
            }
            return bytes;
        }


        [RelayCommand]
        public async void Start()
        {
            if (!serialPort.IsOpen)
            {
                MessageBox.Show("请先打开COM");
                return;
            }

            try
            {
                IsProcessing = true;
                IsProcessingVisiable = Visibility.Visible;
                await Task.Run(async () =>
                {
                    using var reader = new StreamReader(filePath);
                    using var csv = new CsvReader(reader, new CsvConfiguration(CultureInfo.InvariantCulture)
                    {
                        HasHeaderRecord = true,          // 把第一行当标题行
                        IgnoreBlankLines = true,         // 自动跳过空行
                        BadDataFound = _ => { },         // 格式不对的行直接跳过
                        MissingFieldFound = _ => { }     // 缺列的行也跳过
                    });

                    // 关键：先读表头
                    csv.Read();
                    csv.ReadHeader();

                    byte[] start = { 0xEF, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
                    serialPort.Write(start, 0, start.Length);
                    Logger.Info($"Send: {BitConverter.ToString(start).Replace("-", " ")}");

                    int currentRow = 1;
                    while (await csv.ReadAsync())
                    {
                        // currentRow 和 totalRow 都是整数类型（int），那么在进行除法运算时，如果 currentRow 小于 totalRow，结果将会是 0。这是因为整数除法会向下取整。结果转换为Double类型
                        ProcessProgress = (double)currentRow / totalRow * 100;

                        var c = csv.GetField("R/W")?.Trim();
                        var fHex = csv.GetField("Request byte")?.Trim();
                        var hHex = csv.GetField("WData")?.Trim();

                        byte[]? payload = null;

                        if ("read".Equals(c, StringComparison.OrdinalIgnoreCase))
                        {
                            payload = ParseHexString(fHex);
                            if (payload != null)
                            {
                                // read：payload + 4 个 0x00
                                payload = payload.Concat(new byte[4]).ToArray();
                            }
                            Mediator.currentRWType = RWType.read;
                        }
                        else if ("write".Equals(c, StringComparison.OrdinalIgnoreCase))
                        {
                            var left = ParseHexString(fHex);
                            var right = ParseHexString(hHex);

                            if (left != null || right != null)
                            {
                                payload = (left ?? Array.Empty<byte>())
                                           .Concat(right ?? Array.Empty<byte>())
                                           .ToArray();
                            }
                            Mediator.currentRWType = RWType.write;
                        }

                        if (payload != null)
                        {
                            // 最终帧：EF EF + payload
                            var bytesToSend = new byte[] { 0xEF, 0xEF }
                                              .Concat(payload)
                                              .ToArray();

                            serialPort.Write(bytesToSend, 0, bytesToSend.Length);
                            Logger.Info($"Send: {BitConverter.ToString(bytesToSend).Replace("-", " ")}");
                        }
                        await Task.Delay(DelayTime);
                        currentRow++;
                    }
                });
                IsProcessing = false;
                IsProcessingVisiable = Visibility.Collapsed;

            }
            catch (Exception ex)
            {
                Logger.Error(ex.Message);
                IsProcessing = false;
                IsProcessingVisiable = Visibility.Collapsed;

            }
            finally
            {
                serialPort.Close();
                ConnectButtonContent = "Open";
                Logger.Info($"{SelectedPort}断开连接");
                SelectComEnable = true;
                IsProcessing = false;
                IsProcessingVisiable = Visibility.Collapsed;

            }
        }
    }
}
